﻿using System;

namespace CyberConnect.Insteon
{
    internal struct LedMessage : IMessage, IEcho, IEquatable<LedMessage>, IEquatable<byte>, IEquatable<bool>
    {
        private readonly bool _LedState;

        private readonly EchoState _EchoResult;

        public LedMessage(bool state)
            : this(state, 0) { }

        public LedMessage(byte state, EchoState echoResult)
        {
            switch (state)
            {
                case (byte)PlmCommand.PlmLedOn:
                    this._LedState = true;
                    break;

                case (byte)PlmCommand.PlmLedOff:
                    this._LedState = false;
                    break;

                default:
                    throw new ArgumentException("Byte does not represent On or Off", "state");
            }

            this._EchoResult = echoResult;
        }

        public LedMessage(bool state, EchoState echoResult)
        {
            this._LedState = state;

            this._EchoResult = echoResult;
        }

        #region IMessage Members

        /// <summary>
        /// Breaks an IMessage into a byte array that the PLM understands.
        /// </summary>
        /// <returns>A byte array that the PLM understands</returns>
        public byte[] ToBytes()
        {
            byte[] MessageBytes = new byte[2];

            MessageBytes[0] = 2;
            MessageBytes[1] = this.ToByte();

            return MessageBytes;
        }

        #endregion IMessage Members

        #region IEcho Members

        /// <summary>
        /// Returns a value indicating if this message is an Echo.
        /// </summary>
        public bool IsEcho
        {
            get { return this.EchoResult == EchoState.Ack || this.EchoResult == EchoState.Nak; }
        }

        /// <summary>
        /// Returns a value indicating if this echo is a success echo.
        /// </summary>
        public bool IsValidEcho
        {
            get { return IsEcho && this.EchoResult == EchoState.Ack; }
        }

        /// <summary>
        /// Holds the acknowledgement byte of an echo.
        /// </summary>
        public EchoState EchoResult
        {
            get { return _EchoResult; }
        }

        #endregion IEcho Members

        #region Equality and Hashing

        public override int GetHashCode()
        {
            return this._LedState.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            return
                (obj == null) ? false
                    : !(obj is LedMessage)
                        ? !(obj is byte)
                            ? !(obj is bool)
                                ? false
                            : Equals((bool)obj)
                        : Equals((byte)obj)
                    : Equals((LedMessage)obj);
        }

        #region IEquatable<LedMessage> Members

        public bool Equals(LedMessage other)
        {
            return this._LedState == other._LedState;
        }

        #endregion IEquatable<LedMessage> Members

        #region IEquatable<byte> Members

        public bool Equals(byte other)
        {
            return this.ToByte() == other;
        }

        #endregion IEquatable<byte> Members

        #region IEquatable<bool> Members

        public bool Equals(bool other)
        {
            return this._LedState == other;
        }

        #endregion IEquatable<bool> Members

        public static bool operator ==(LedMessage leftValue, LedMessage rightValue)
        {
            return leftValue.Equals(rightValue);
        }

        public static bool operator ==(LedMessage leftValue, byte rightValue)
        {
            return leftValue.Equals(rightValue);
        }

        public static bool operator ==(LedMessage leftValue, bool rightValue)
        {
            return leftValue.Equals(rightValue);
        }

        public static bool operator !=(LedMessage leftValue, LedMessage rightValue)
        {
            return !(leftValue == rightValue);
        }

        public static bool operator !=(LedMessage leftValue, byte rightValue)
        {
            return !(leftValue == rightValue);
        }

        public static bool operator !=(LedMessage leftValue, bool rightValue)
        {
            return !(leftValue == rightValue);
        }

        #endregion Equality and Hashing

        private byte ToByte()
        {
            return (byte)(this._LedState ? PlmCommand.PlmLedOn : PlmCommand.PlmLedOff);
        }
    }
}